import JoyStickTypeFollow from "./TypeFollow";
import JoyStickTypeFixed from "./TypeFixed";
import JoyStickTypeDelta from "./TypeDelta";
import { JoyStickTypeBase } from "./TypeBase";

const { ccclass, property } = cc._decorator;

export enum JoySickType {
    FIXED,  //固定摇杆
    FOLLOW, //跟随摇杆
    DELTA,  //偏移量摇杆
}

export enum DirectionType {
    FOUR,
    EIGHT,
    ALL,
}

export interface IJoyStickType {
    touchStartEvent(event: cc.Event.EventTouch): boolean
    touchMoveEvent(event: cc.Event.EventTouch): boolean
    touchEndEvent(event: cc.Event.EventTouch): boolean
    init(): void
}

@ccclass
export default class JoyStick extends cc.Component {

    static get EvtStart(): string { return "摇杆激活" }
    static get EvtUpdate(): string { return "摇杆跟新状态" }
    static get EvtReset(): string { return "摇杆复位" }
    static get EvtCancel(): string { return "取消摇杆" }

    @property({ type: cc.Enum(JoySickType) })
    joySickType = JoySickType.FIXED

    @property({ type: cc.Enum(DirectionType) })
    directionType = DirectionType.ALL

    @property({ type: cc.Node })
    dot: cc.Node = null

    @property({ type: cc.Node })
    ring: cc.Node = null

    @property({ type: cc.Node })
    show: cc.Node = null

    _radius: number = 0
    _limitRect: cc.Rect = cc.rect()
    _stickPos: cc.Vec3 = cc.v3()
    _touchLocation: cc.Vec2 = cc.v2()
    _stickImpl: IJoyStickType = null
    _distancePercent: number = 0
    _minDistancePercent: number = 0

    createImpl(): IJoyStickType {
        let imp: IJoyStickType = null
        switch (this.joySickType) {
            case JoySickType.FOLLOW:
                imp = new JoyStickTypeFollow(this)
                break
            case JoySickType.FIXED:
                imp = new JoyStickTypeFixed(this)
                break
            case JoySickType.DELTA:
                imp = new JoyStickTypeDelta(this)
                break
            default:
                cc.error("未知的摇杆类型")
        }
        if (imp) {
            imp.init()
            cc.log("摇杆初始化")
        }
        return imp
    }

    private _initTouchEvent() {
        this.node.on(cc.Node.EventType.TOUCH_START, this._touchStartEvent, this)
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this._touchMoveEvent, this)
        this.node.on(cc.Node.EventType.TOUCH_END, this._touchEndEvent, this)
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this._touchEndEvent, this)
    }

    private _touchStartEvent(event: cc.Event.EventTouch) {
        if (!this._stickImpl.touchStartEvent(event)) {
            return
        }
        //Facade.getInstance().getModel(JoyStickModel).Update(true, null)
        this.node.emit(JoyStick.EvtStart)
        this._touchMoveEvent(event)
        //cc.log(event.getLocation() + "==>" + touchPos)
    }
    private _touchMoveEvent(event: cc.Event.EventTouch) {
        if (!this._stickImpl.touchMoveEvent(event)) {
            return
        }
        let tPos = event.getLocation()
        const touchPos = this.ring.convertToNodeSpaceAR(tPos)
        let distance = touchPos.mag()

        const posX = this._stickPos.x + touchPos.x
        const posY = this._stickPos.y + touchPos.y

        const p = cc.v2(posX, posY).sub(this.ring.getPosition()).normalize()
        if (this._radius > distance) {
            this.dot.setPosition(cc.v2(posX, posY))
        } else {
            distance = this._radius
            const x = this._stickPos.x + p.x * this._radius
            const y = this._stickPos.y + p.y * this._radius
            this.dot.setPosition(cc.v2(x, y))
        }
        //Facade.getInstance().getModel(JoyStickModel).Update(true, p)
        this._distancePercent = distance / this._radius
        if (this._distancePercent > this._minDistancePercent) {
            this._distancePercent -= this._minDistancePercent
            this.node.emit(JoyStick.EvtUpdate, p, this._distancePercent)
        } else {
            this._distancePercent = 0
        }
        //cc.log(event.getLocation() + "==>" + touchPos)
    }
    private _touchEndEvent(event: cc.Event.EventTouch) {
        if (!this._stickImpl.touchEndEvent(event)) {
            return
        }
        this.dot.setPosition(this.ring.getPosition())
        //Facade.getInstance().getModel(JoyStickModel).Update(false, null)
        if (this._distancePercent == 0) {
            this.node.emit(JoyStick.EvtCancel)
        } else {
            this.node.emit(JoyStick.EvtReset)
        }
    }

    // LIFE-CYCLE CALLBACKS:

    onLoad() {
        this.dot.setPosition(this.ring.getPosition())
        this._radius = this.ring.width / 2
        this._limitRect.x = this.dot.width / 2
        this._limitRect.y = this.dot.height / 2
        this._limitRect.width = this.node.width - this.dot.width
        this._limitRect.height = this.node.width - this.dot.height
        this._initTouchEvent()
        this._stickImpl = this.createImpl()
    }

    start() {
    }

    update(dt: number) { }
}
